home *** CD-ROM | disk | FTP | other *** search
- /* @(#)util/mkdbm.c 1.8 7/11/92 11:40:03 */
-
- /*
- * Copyright (C) 1987, 1988 Ronald S. Karr and Landon Curt Noll
- * Copyright (C) 1992 Ronald S. Karr
- *
- * See the file COPYING, distributed with smail, for restriction
- * and warranty information.
- */
-
- /*
- * mkdbm.c:
- * Take a list of lines with a key followed by a colon character
- * or white space followed by data and build a dbm database from
- * them. If the flag -f is given, downcase the keys.
- *
- * Usage: mkdbm [-o database] [-fvndy] [input_file ...]
- */
- #include <stdio.h>
- #include <ctype.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include "defs.h"
- #include "smail.h"
- #include "dys.h"
- #include "exitcodes.h"
- #include "dbm_compat.h"
- #ifndef DEPEND
- # include "extern.h"
- #endif
-
- #if !defined(HAVE_GETHOSTNAME) && defined(HAVE_UNAME)
- #include <sys/utsname.h>
- #endif
-
- char *program; /* argv[0] from main */
- /* variables local to this file */
- static char *out_name = NULL;
- static char *temp_dir = NULL;
- static char *temp_pag = NULL;
- static int downcase = FALSE;
- static int ypstamps = FALSE;
- static int verbose = FALSE;
- static int no_at_record = FALSE;
- static int no_nul_byte = FALSE;
- static int reccnt = 0;
- static int maxlen = 0;
-
- /* functions local to this file */
- static void done();
- static char **read_args();
- static char *build_temp_name();
- static void create_database();
- static void add_to_database();
- static void add_ending_record();
- static char *getline();
- static void rename_database();
-
- /*ARGSUSED*/
- void
- main(argc, argv)
- int argc;
- char **argv;
- {
- char **files;
- char *temp_name;
-
- program = *argv++;
-
- files = read_args(argv);
-
- if (out_name == NULL) {
- if (files[0] && ! EQ(files[0], "-")) {
- out_name = files[0];
- } else {
- out_name = "dbm";
- }
- }
-
- temp_name = build_temp_name(out_name);
- create_database(temp_name);
-
- if (*files) {
- while (*files) {
- FILE *f;
-
- if (EQ(*files, "-")) {
- add_to_database(stdin);
- files++;
- continue;
- }
- f = fopen(*files, "r");
- if (f == NULL) {
- (void) fprintf(stderr, "%s: cannot open ", program);
- (void) perror(*files);
- done(EX_NOINPUT);
- }
- add_to_database(f);
- files++;
- }
- } else {
- add_to_database(stdin);
- }
-
-
- if (ypstamps) {
- add_yp_stamps();
- }
-
- if (! no_at_record) {
- add_ending_record();
- }
-
- rename_database(temp_name, out_name);
-
- if (verbose) {
- (void) printf("Added %d records, longest record was %d bytes\n",
- reccnt, maxlen);
- }
-
- dbmclose();
- exit(EX_OK);
- }
-
- add_yp_stamps()
- {
- datum key_lastmod, val_lastmod;
- datum key_master, val_master;
- long now;
- char nows[32];
-
- #ifdef HAVE_GETHOSTNAME
- char host[256];
-
- if(gethostname(host, sizeof(host)) < 0) {
- done(EX_DATAERR);
- }
- #else
- #ifdef HAVE_UNAME
- struct utsname utsname;
- char *host;
-
- (void) uname(&utsname);
- host = utsname.nodename;
- #else
- #ifdef SITENAME_FILE
- char host[4096];
- FILE *f;
- char *p;
-
- f = fopen(SITENAME_FILE, "r");
- if (f == NULL) {
- fprintf(stderr, "%s: cannot open ", program);
- perror(SITENAME_FILE);
- done(EX_OSFILE);
- }
- host[0] = '\0';
- fgets(host, sizeof(host), f);
- if (host[0] == '\0') {
- fprintf(stderr, "%s: no hostname found in %s\n",
- program, SITENAME_FILE);
- exit(EX_OSFILE);
- }
- p = strchr(host, '\n');
- if (p)
- *p = '\0';
- fclose(f);
- #else
- fprintf(stderr, "%s: No known method for computing hostname\n",
- program);
- done(EX_USAGE);
- #endif /* SITENAME_FILE */
- #endif /* HAVE_UNAME */
- #endif /* HAVE_GETHOSTNAME */
-
- (void) time(&now);
- sprintf(nows, "%10.10ld", now);
-
- key_lastmod.dptr = "YP_LAST_MODIFIED";
- key_lastmod.dsize = strlen(key_lastmod.dptr);
- val_lastmod.dptr = nows;
- val_lastmod.dsize = strlen(val_lastmod.dptr);
-
- key_master.dptr = "YP_MASTER_NAME";
- key_master.dsize = strlen(key_master.dptr);
- val_master.dptr = host;
- val_master.dsize = strlen(val_master.dptr);
-
- if (store(key_lastmod, val_lastmod) < 0) {
- (void) fprintf(stderr, "%s: store failed for %s\n",
- program, key_lastmod.dptr);
- done(EX_DATAERR);
- }
-
- if (store(key_master, val_master) < 0) {
- (void) fprintf(stderr, "%s: store failed for %s\n",
- program, key_master.dptr);
- done(EX_DATAERR);
- }
- }
-
- /*
- * for errors or signals, remove the temp files
- */
- static void
- done(ex)
- int ex;
- {
- dbmclose();
- (void) unlink(temp_dir);
- (void) unlink(temp_pag);
- exit(ex);
- }
-
- /*
- * read through the arglist and turn argv into list of input files
- */
- static char **
- read_args(args)
- char **args;
- {
- char **filev = args;
- char **filep = args;
-
- while (*args) {
- if ((*args)[0] == '-' && (*args)[1] != '\0') {
- static char *end_arg = "";
- char *s = &(*args)[1];
-
- while (*s) {
- switch (*s++) {
- case 'y':
- ypstamps = TRUE;
- break;
-
- case 'f':
- downcase = TRUE;
- break;
-
- case 'v':
- verbose = TRUE;
- break;
-
- case 'n':
- no_nul_byte = TRUE;
- break;
-
- case 'd':
- no_at_record = TRUE;
- break;
-
- case 'o':
- if (*s != '\0') {
- out_name = s;
- s = end_arg;
- } else {
- out_name = *++args;
- }
- break;
-
- default:
- (void) fprintf(stderr,
- "Usage: %s [-yfvnd] [-o database] [file ...]\n",
- program);
- exit(EX_USAGE);
- }
- }
- } else {
- *filep++ = *args;
- }
- args++;
- }
-
- *filep = NULL;
- return filev;
- }
-
- /*
- * build a temp filename in the same directory as the given file
- */
- static char *
- build_temp_name(name)
- char *name;
- {
- char *fn;
- char *slash = rindex(name, '/');
- extern char *mktemp();
-
- if (slash) {
- fn = xmalloc((unsigned)(slash - name + sizeof("/dbmXXXXXX")));
- (void) strncpy(fn, name, slash - name);
- (void) strcat(fn, "/dbmXXXXXX");
- } else {
- fn = xmalloc(sizeof("dbmXXXXXX"));
- strcpy(fn, "dbmXXXXXX");
- }
- return mktemp(fn);
- }
-
- /*
- * create a DBM database with the given basename
- */
- static void
- create_database(dbm_name)
- char *dbm_name;
- {
- int fd;
- int temp_len = strlen(dbm_name);
-
- temp_dir = xmalloc(temp_len + sizeof(".dir"));
- temp_pag = xmalloc(temp_len + sizeof(".pag"));
- (void) sprintf(temp_dir, "%s.dir", dbm_name);
- (void) sprintf(temp_pag, "%s.pag", dbm_name);
-
- fd = creat(temp_dir, 0644);
- if (fd < 0) {
- (void) fprintf(stderr, "%s: cannot creat ", program);
- (void) perror(temp_dir);
- exit(EX_TEMPFAIL);
- }
- (void) close(fd);
-
- fd = creat(temp_pag, 0644);
- if (fd < 0) {
- (void) fprintf(stderr, "%s: cannot creat ", program);
- (void) perror(temp_pag);
- (void) unlink(temp_dir);
- exit(EX_TEMPFAIL);
- }
- (void) close(fd);
-
- /* open the new DBM database */
- if (dbminit(dbm_name) < 0) {
- (void) fprintf(stderr, "%s: dbminit failed ", program);
- (void) perror(dbm_name);
- done(EX_TEMPFAIL);
- }
- }
-
- /*
- * add all entries in the file to the DBM database
- */
- static void
- add_to_database(f)
- FILE *f;
- {
- register char *s;
-
- while (s = getline(f)) {
- register char *data;
- datum key, content;
-
- for (data = s; *data && *data != ':' && !isspace(*data); data++) ;
-
- if (*data) {
- *data++ = '\0';
- key.dptr = s;
- key.dsize = data - s - 1;
- content.dptr = data;
- content.dsize = strlen(data);
- if (! no_nul_byte) {
- key.dsize++;
- content.dsize++;
- }
- if (downcase) {
- register char *sp;
-
- for (sp = s; *sp; sp++) {
- *sp = lowercase(*sp);
- }
- }
- if (store(key, content) < 0) {
- (void) fprintf(stderr, "%s: store failed for %s\n",
- program, s);
- done(EX_DATAERR);
- }
- reccnt++;
- if (content.dsize + key.dsize > maxlen) {
- maxlen = content.dsize + key.dsize;
- }
- } else {
- (void) fprintf(stderr, "%s: no value for key %s, ignored\n",
- program, s);
- }
- }
- }
-
- /*
- * add the ending `@' record, to make sendmail happy.
- */
- static void
- add_ending_record()
- {
- datum key, content;
-
- content.dptr = key.dptr = "@";
- content.dsize = key.dsize = (no_nul_byte? 1: 2);
- if (store(key, content) < 0) {
- (void) fprintf(stderr, "%s: store failed for end record\n", program);
- }
- }
-
- /*
- * read and return one line from the given file.
- *
- * return NULL on end of input.
- */
- static char *
- getline(f)
- register FILE *f;
- {
- static struct str str;
- static int inited = FALSE;
- register int c;
-
- if (! inited) {
- STR_INIT(&str);
- inited = TRUE;
- } else {
- str.i = 0;
- }
- while ((c = getc(f)) != EOF && c != '\n') {
- STR_NEXT(&str, c);
- }
- if (c == EOF && str.i == 0) {
- return NULL;
- }
- STR_NEXT(&str, '\0');
- return str.p;
- }
-
- /*
- * rename the database from the old name to a new one.
- *
- * Allow some time after unlinking the old name so that smail will not
- * open the .dir file of the old database and the .pag file of the new
- * one accidentally.
- */
- static void
- rename_database(from, to)
- char *from;
- char *to;
- {
- unsigned int fromlen = (unsigned)strlen(from);
- unsigned int tolen = (unsigned)strlen(to);
- char *from_dir = xmalloc(fromlen + sizeof(".dir"));
- char *from_pag = xmalloc(fromlen + sizeof(".pag"));
- char *to_dir = xmalloc(tolen + sizeof(".dir"));
- char *to_pag = xmalloc(tolen + sizeof(".pag"));
-
- (void) sprintf(from_dir, "%s.dir", from);
- (void) sprintf(from_pag, "%s.pag", from);
- (void) sprintf(to_dir, "%s.dir", to);
- (void) sprintf(to_pag, "%s.pag", to);
-
- (void) unlink(to_dir);
- (void) unlink(to_pag);
- (void) sleep(2); /* sleep at least 1 second */
- if (link(from_dir, to_dir) < 0) {
- (void) fprintf(stderr, "%s: cannot link %s to ", program, from_dir);
- (void) perror(to_dir);
- done(EX_CANTCREAT);
- }
- if (link(from_pag, to_pag) < 0) {
- (void) fprintf(stderr, "%s: cannot link %s to ", program, from_pag);
- (void) perror(to_pag);
- done(EX_CANTCREAT);
- }
- (void) unlink(from_dir);
- (void) unlink(from_pag);
- }
-
- /*
- * standalone versions of some referenced routines
- */
- char *
- xmalloc(len)
- unsigned int len;
- {
- char *malloc();
- register char *ret = malloc(len);
-
- if (ret == NULL) {
- (void) fprintf(stderr, "%s: out of memory!\n", program);
- exit(EX_OSERR);
- }
- return ret;
- }
-
- char *
- xrealloc(s, len)
- char *s;
- unsigned int len;
- {
- char *realloc();
- register char *ret = realloc(s, len);
-
- if (ret == NULL) {
- (void) fprintf(stderr, "%s: out of memory!\n", program);
- exit(EX_OSERR);
- }
- return ret;
- }
-